home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / intrvews / xgrab.lha / xgrab / ui / textviewer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-04-25  |  17.7 KB  |  770 lines

  1. /**
  2.    GRAB Graph Layout and Browser System
  3.  
  4.    Copyright (c) 1987, 1988, 1989 Stanford University
  5.    Copyright (c) 1989, Tera Computer Company
  6.  **/
  7.  
  8.   /**
  9.      stolen from the InterViews 2.5 source files (text directory, which 
  10.      is unsupported in 2.6.  
  11.    **/
  12.  
  13. /*
  14.  * TextViewer - basic text buffer
  15.  */
  16.  
  17. #include <InterViews/scene.h>
  18. #include "textviewer.h"
  19. #include <InterViews/shape.h>
  20. #include <InterViews/perspective.h>
  21. #include <InterViews/sensor.h>
  22. #include <InterViews/Std/bstring.h>
  23. /*#include <bstring.h>*/
  24. #include <string.h>
  25.  
  26. static const float pagefract = 0.8;        // fraction of page to scroll
  27.  
  28. void TPainter::StyledText (Canvas* c, const char* p, int len, StyleSet) {
  29.     // styles not implemented yet
  30.     Text(c, p, len);
  31. }
  32.  
  33. TextLine::TextLine () {
  34.     size = 0;
  35.     length = 0;
  36.     text = nil;
  37.     attr = nil;
  38.     above = nil;
  39.     below = nil;
  40.     touched = true;
  41. }
  42.  
  43. TextLine::~TextLine () {
  44.     delete text;
  45.     delete attr;
  46. }
  47.  
  48. void TextLine::Size (int s) {
  49.     if (s <= size && size != 0) {
  50.     return;
  51.     }
  52.     int newsize = s<8 ? 8 : s<32 ? 32 : s<128 ? 128 : s<1024 ? 1024 : s;
  53.     char* newtext = new char[newsize];
  54.     bzero(newtext, newsize);
  55.     bcopy(text, newtext, min(size, newsize));
  56.     char* newattr = new char[newsize];
  57.     bzero(newattr, newsize);
  58.     bcopy(attr, newattr, min(size, newsize));
  59.     delete text;
  60.     text = newtext;
  61.     delete attr;
  62.     attr = newattr;
  63.     size = newsize;
  64. }
  65.  
  66. void TextLine::Replace (int index, const char* s, int len, char a) {
  67.     Size(index+len);
  68.     for (int i = 0; i<len; ++i) {
  69.     text[i+index] = s[i];
  70.     attr[i+index] = a;
  71.     }
  72.     length = max(length, index+len);
  73.     touched = true;
  74. }    
  75.  
  76. void TextLine::Insert (int index, const char* s, int len, char a) {
  77.     Size(length+len);
  78.     bcopy(text+index, text+index+len, length-index);
  79.     for (int i = 0; i<len; ++i) {
  80.     text[i+index] = s[i];
  81.     attr[i+index] = a;
  82.     }
  83.     length += len;
  84.     touched = true;
  85. }
  86.  
  87. void TextLine::Blank (int index, int len) {
  88.     Size(index+len);
  89.     for (int i = index; i<length && i<index+len; ++i) {
  90.     text[i] = ' ';
  91.     attr[i] = '\0';
  92.     }
  93.     length = max(length, index+len);
  94.     touched = true;
  95. }
  96.  
  97. void TextLine::Delete (int index, int len) {
  98.     int l = min(len, length-index);
  99.     bcopy(text+index+l, text+index, length-index-l);
  100.     bcopy(attr+index+l, attr+index, length-index-l);
  101.     length -= l;
  102.     text[length] = '\0';
  103.     attr[length] = '\0';
  104.     touched = true;
  105. }
  106.  
  107. void TextLine::EndLine (int index) {
  108.     Size(index);
  109.     length = index;
  110.     text[length] = '\0';
  111.     attr[length] = '\0';
  112.     touched = true;
  113. }
  114.  
  115. TextLine* TextLine::Split (int index) {
  116.     TextLine* newline = new TextLine;
  117.     newline->Size(length-index);
  118.     bcopy(text+index, newline->text, length-index);
  119.     bcopy(attr+index, newline->attr, length-index);
  120.     newline->length = length-index;
  121.     length = index;
  122.     text[length] = '\0';
  123.     attr[length] = '\0';
  124.     touched = true;
  125.     return newline;
  126. }
  127.  
  128. void TextLine::Merge (TextLine* line) {
  129.     Size(length+line->length);
  130.     bcopy(line->text, text+length, line->length);
  131.     bcopy(line->attr, attr+length, line->length);
  132.     length += line->length;
  133.     touched = true;
  134. }
  135.  
  136. TextViewer::TextViewer (Painter* out, int cols, int rows) : (allEvents, out) {
  137.     overwrite = true;
  138.     buffer = true;
  139.     viewcaret = true;
  140.     caretstyle = None;
  141.  
  142.     painter = new TPainter(output);
  143.     highlight = new TPainter(output);
  144.     highlight->Reverse();
  145.  
  146.     shape->hunits = painter->GetFont()->Width("n");
  147.     shape->vunits = painter->GetFont()->Height();
  148.     shape->width = shape->hunits * cols;
  149.     shape->height = shape->vunits * rows;
  150.  
  151.     perspective = new Perspective;
  152.     perspective->Init(1, -1, cols, 1);
  153.     perspective->sy = 1;
  154.     perspective->ly = int(perspective->curheight * pagefract);
  155.     perspective->sx = 1;
  156.     perspective->lx = int(perspective->curwidth * pagefract);
  157.  
  158.     top = bottom = new TextLine;
  159.     top->Insert(0, "", 0, 0);
  160.  
  161.     prow = perspective->y0 + perspective->height - 1;
  162.     prev = top;
  163.  
  164.     row = prow;
  165.     col = perspective->x0;
  166.     dot = FindLine(row);
  167.  
  168.     crow = 0;
  169.     ccol = 0;
  170.     caret = nil;
  171.  
  172.     margin = 0;
  173. }
  174.  
  175. TextViewer::~TextViewer () {
  176.     delete painter;
  177.     delete highlight;
  178.     while (top != nil) {
  179.     TextLine* doomed = top;
  180.     top = top->below;
  181.     delete doomed;
  182.     }
  183. }
  184.  
  185. Coord TextViewer::YPix (Coord y) {
  186.     return
  187.     ymax+1 - (perspective->cury+perspective->curheight-y) * shape->vunits;
  188. }
  189.  
  190. Coord TextViewer::YChar (Coord y) {
  191.     return
  192.     perspective->cury + perspective->curheight-1 - (ymax-y)/shape->vunits;
  193. }
  194.  
  195. Coord TextViewer::XPix (TextLine* line, Coord x) {
  196.     Coord xx = x - perspective->x0;
  197.     Font* f = painter->GetFont();
  198.     Coord ww = (line->text != nil) ? f->Width(line->text, xx) : 0;
  199.     return ww - (perspective->curx-perspective->x0) * shape->hunits;
  200. }
  201.  
  202. Coord TextViewer::XChar (TextLine* line, Coord x) {
  203.     Coord xx = x + (perspective->curx-perspective->x0) * shape->hunits;
  204.     Font* f = painter->GetFont();
  205.     Coord index = (line->text != nil) ?
  206.     f->Index(line->text, line->length, xx, false) : 0;
  207.     return index + perspective->x0 - 1;
  208. }
  209.  
  210. void TextViewer::ToPix (Coord& x, Coord& y) {
  211.     x = XPix(FindLine(y), x);
  212.     y = YPix(y);
  213. }
  214.  
  215. void TextViewer::ToChar (Coord& x, Coord& y) {
  216.     y = YChar(y);
  217.     x = XChar(FindLine(y), x);
  218. }
  219.  
  220. TextLine* TextViewer::FindLine (Coord y) {        // y in char coords
  221.     if (y > prow) {
  222.     while (y > prow && prev->above != nil) {
  223.         ++prow;
  224.         prev = prev->above;
  225.     }
  226.     } else if (y < prow) {
  227.     while (y < prow && prev->below != nil) {
  228.         --prow;
  229.         prev = prev->below;
  230.     }
  231.     }
  232.     return prev;
  233. }
  234.  
  235. void TextViewer::Position (TextLine*& line, Coord& r, Coord& c) {
  236.     r = max(r, perspective->y0);
  237.     r = min(r, perspective->y0 + perspective->height - 1);
  238.     while ((line = FindLine(r)) != top && line->size == 0) {
  239.     ++r;
  240.     }
  241.     c = max(c, perspective->x0);
  242.     if (c > line->length+1) {
  243.     c = line->length+1;
  244.     }
  245. }
  246.  
  247. void TextViewer::AddLine (TextLine* before, TextLine* newLine) {
  248.     if (before == nil) {
  249.     newLine->above = bottom;
  250.     newLine->below = nil;
  251.     newLine->above->below = newLine;
  252.     bottom = newLine;
  253.     } else if (before == top) {
  254.     newLine->above = nil;
  255.     newLine->below = before;
  256.     newLine->below->above = newLine;
  257.     top = newLine;
  258.     } else {
  259.     newLine->above = before->above;
  260.     newLine->below = before;
  261.     newLine->above->below = newLine;
  262.     newLine->below->above = newLine;
  263.     }
  264. }
  265.  
  266. void TextViewer::AddLines (TextLine* before, int count) {
  267.     if (count == 0) {
  268.     return;
  269.     }
  270.     while (count > 0) {
  271.     TextLine* newLine = new TextLine;
  272.     newLine->EndLine(0);
  273.     AddLine(before, newLine);
  274.     if (
  275.         before != nil
  276.         && perspective->curheight == perspective->height
  277.         && bottom->size==0
  278.     ) {
  279.         RemoveLine(nil);
  280.     } else {
  281.         ++perspective->height;
  282.         --perspective->y0;
  283.     }
  284.     --count;
  285.     }
  286.     prow = perspective->y0 + perspective->height - 1;
  287.     prev = top;
  288.     dot = FindLine(row);
  289. }
  290.  
  291. void TextViewer::RemoveLine (TextLine* before) {
  292.     TextLine* doomed = (before==nil) ? bottom : before->above;
  293.     if (doomed == top) {
  294.     top = doomed->below;
  295.     doomed->below->above = nil;
  296.     } else if (doomed == bottom) {
  297.     doomed->above->below = nil;
  298.     bottom = doomed->above;
  299.     } else if (doomed != nil) {
  300.     doomed->above->below = doomed->below;
  301.     doomed->below->above = doomed->above;
  302.     }
  303.     delete doomed;
  304. }
  305.  
  306. void TextViewer::RemoveLines (TextLine* before, int count) {
  307.     if (count == 0) {
  308.     return;
  309.     }
  310.     boolean draw = false;
  311.     while (count > 0) {
  312.     RemoveLine(before);
  313.     --perspective->height;
  314.     ++perspective->y0;
  315.     --count;
  316.     }
  317.     while (perspective->curheight > perspective->height) {
  318.     AddLine(nil, new TextLine);
  319.     ++perspective->height;
  320.     --perspective->y0;
  321.     draw = true;
  322.     }
  323.     if (perspective->cury < perspective->y0) {
  324.     perspective->cury = perspective->y0;
  325.     draw = true;
  326.     }
  327.     prow = perspective->y0 + perspective->height - 1;
  328.     prev = top;
  329.     dot = FindLine(row);
  330.     if (draw) {
  331.     Draw();
  332.     }
  333. }
  334.  
  335. void TextViewer::DrawLine(TextLine* line, 
  336.     Coord baseline, Coord first, Coord last
  337. ) {
  338.     if (canvas == nil) {
  339.     return;
  340.     }
  341.     Coord f = max(first, perspective->x0);
  342.     Coord l = min(last, line->length-1+perspective->x0);
  343.     if (last >= line->length-1+perspective->x0) {
  344.     if (
  345.         line->size > 0 && line->length > 0 &&
  346.         StyleSet(line->attr[line->length-1]).Includes(Reversed)
  347.     ) {
  348.         highlight->ClearRect(canvas, 
  349.         XPix(line, l+1), baseline, xmax, baseline+shape->vunits-1
  350.         );
  351.     } else {
  352.         painter->ClearRect(canvas, 
  353.         XPix(line, l+1), baseline, xmax, baseline+shape->vunits-1
  354.         );
  355.     }
  356.     }
  357.     if (line->size == 0 || l<f) {
  358.     return;
  359.     }
  360.     char* cp = line->text+f-perspective->x0;
  361.     char* ap = line->attr+f-perspective->x0;
  362.     char* start = cp;
  363.     char* finish = line->text+l-perspective->x0;
  364.     char a = *ap;
  365.     for (;;) {
  366.     if (*ap != a || cp > finish) {
  367.         TPainter* p;
  368.         if (StyleSet(a).Includes (Reversed)) {
  369.         p = highlight;
  370.         } else {
  371.         p = painter;
  372.         }
  373.         p->MoveTo(XPix(line, start-line->text+perspective->x0), baseline);
  374.         p->StyledText(canvas, start, cp-start, StyleSet(a));
  375.         if (cp>finish) {
  376.         break;
  377.         } else {
  378.         start = cp;
  379.         a = *ap;
  380.         }
  381.     } else {
  382.         ++cp; ++ap;
  383.     }
  384.     }
  385. }
  386.  
  387. void TextViewer::FlushLine (TextLine* line, Coord baseline) {
  388.     if (line->touched) {
  389.     DrawLine(line, baseline, XChar(line, 0), XChar(line, xmax));
  390.     line->touched = false;
  391.     }
  392. }
  393.  
  394. void TextViewer::HideCaret () {
  395.     if (caret == nil) {
  396.     return;
  397.     }
  398.     DrawLine(caret, YPix(crow), ccol, ccol);
  399. }
  400.  
  401. void TextViewer::ShowCaret () {
  402.     if (caret == nil || canvas == nil) {
  403.     return;
  404.     }
  405.     Coord caretx = XPix(caret, ccol);
  406.     Coord carety = YPix(crow);
  407.  
  408.     char c;
  409.     StyleSet s;
  410.     if (caret->text != nil && ccol <= caret->length-1+perspective->x0) {
  411.     c = caret->text[ccol-perspective->x0];
  412.     s = StyleSet(caret->attr[ccol-perspective->x0]);
  413.     } else {
  414.     c = ' ';
  415.     }
  416.     int width = painter->GetFont()->Width(&c, 1);
  417.     int height = shape->vunits;
  418.  
  419.     Painter* p, *hl;
  420.     if (s.Includes(Reversed)) {
  421.     p = highlight; hl = painter;
  422.     } else {
  423.     p = painter; hl = highlight;
  424.     }
  425.     switch (caretstyle) {
  426.     case None:
  427.     break;
  428.     case Bar:
  429.     p->Line(canvas, caretx, carety, caretx, carety+height-1);
  430.     break;
  431.     case Block:
  432.     hl->MoveTo(caretx, carety);
  433.     hl->Text(canvas, &c, 1    );
  434.     break;
  435.     case Outline:
  436.     p->Rect(canvas, caretx, carety, caretx+width-1, carety+height-1);
  437.     break;
  438.     case Underline:
  439.     p->Rect(canvas, caretx, carety, caretx+width-1, carety+1);
  440.     break;
  441.     default:
  442.     break;
  443.     }
  444. }
  445.  
  446. void TextViewer::BringToView (Coord l, Coord c) {
  447.     boolean draw = false;
  448.     if (l < perspective->cury) {
  449.     perspective->cury = max(l-perspective->curheight/2, perspective->y0);
  450.     draw = true;
  451.     }
  452.     if (l > perspective->cury + perspective->curheight - 1) {
  453.     perspective->cury = min(
  454.         l-perspective->curheight/2, 
  455.         perspective->y0+perspective->height-perspective->curheight
  456.     );
  457.     draw = true;
  458.     }
  459.     Coord xx = XPix(FindLine(l), c);
  460.     if (xx < shape->hunits && perspective->curx > perspective->x0) {
  461.     perspective->curx = max(
  462.         perspective->curx + (xx-xmax/2)/shape->hunits, 
  463.         perspective->x0
  464.     );
  465.     draw = true;
  466.     }
  467.     if (xx > xmax) {
  468.     perspective->curx = min(
  469.         perspective->curx + (xx-xmax/2)/shape->hunits, 
  470.         perspective->x0+perspective->width-perspective->curwidth
  471.     );
  472.     draw = true;
  473.     }
  474.     if (draw) {
  475.     Draw();
  476.     }
  477. }
  478.  
  479. void TextViewer::Draw () {
  480.     perspective->Update();
  481.     Redraw(0, 0, xmax, ymax);
  482. }
  483.  
  484. void TextViewer::Redraw (Coord x1, Coord y1, Coord x2, Coord y2) {
  485.     HideCaret();
  486.     if (x1==x2 || y1==y2) {
  487.     return;
  488.     }
  489.     if (y1 < (ymax+1) % shape->vunits) {
  490.     y1 = (ymax+1) % shape->vunits;
  491.     }
  492.     TextLine* begin = FindLine(YChar(y1));
  493.     TextLine* end = FindLine(YChar(y2))->above;
  494.     Coord baseline = YPix(YChar(y1));
  495.     for (TextLine* t = begin; t != end; t = t->above) {
  496.     DrawLine(t, baseline, XChar(t, x1), XChar(t, x2)+1);
  497.     baseline += shape->vunits;
  498.     }
  499.     ShowCaret();
  500. }
  501.  
  502. void TextViewer::Handle (Event&) {
  503. }
  504.  
  505. void TextViewer::Resize () {
  506.     Coord rows = (ymax+1)/shape->vunits;
  507.     perspective->curheight = rows;
  508.     if (perspective->cury > -rows) {
  509.     perspective->cury = -rows;
  510.     }
  511.     if (perspective->height < rows) {
  512.     while (rows > perspective->height) {
  513.         AddLine(nil, new TextLine);
  514.         ++perspective->height;
  515.     }
  516.     perspective->y0 = -rows;
  517.     perspective->cury = -rows;
  518.     } else if (perspective->cury == perspective->y0) {
  519.     while (perspective->height > rows && bottom->size==0) {
  520.         RemoveLine(nil);
  521.         --perspective->height;
  522.         ++perspective->y0;
  523.         ++perspective->cury;
  524.     }
  525.     }
  526.     Coord cols = (xmax+1)/shape->hunits;
  527.     Coord width = 0;
  528.     for (TextLine* l = top; l != nil; l = l->below) {
  529.     if (l->text != nil) {
  530.         width = max(
  531.         width, 
  532.         painter->GetFont()->Width(l->text, l->length)
  533.         );
  534.     }
  535.     }
  536.     perspective->curwidth = cols;
  537.     perspective->width = width/shape->hunits;
  538.  
  539.     if (perspective->curx+cols > perspective->width+1) {
  540.     perspective->curx = perspective->width + 1 - cols;
  541.     }
  542.     if (perspective->width < cols) {
  543.     perspective->width = cols;
  544.     perspective->x0 = 1;
  545.     perspective->curx = 1;
  546.     }
  547.     perspective->ly = int(perspective->curheight * pagefract);
  548.     perspective->lx = int(perspective->curwidth * pagefract);
  549.     dot = FindLine(row);
  550. }
  551.  
  552. void TextViewer::Adjust (Perspective& p) {
  553.     int mincury = perspective->y0;
  554.     int maxcury = perspective->y0+perspective->height-perspective->curheight;
  555.     perspective->cury = max(mincury, min(p.cury, maxcury));
  556.     perspective->curx = p.curx;
  557.     Draw();
  558. }
  559.  
  560. void TextViewer::Reshape (Shape& s) {
  561.     *shape = s;
  562.     if (Parent() != nil) {
  563.     Parent()->Change(this);
  564.     }
  565. }
  566.  
  567. void TextViewer::NoCaret () {
  568.     HideCaret();
  569.     caret = nil;
  570.     crow = 0;
  571.     ccol = 0;
  572. }
  573.  
  574. void TextViewer::Caret () {
  575.     HideCaret();
  576.     crow = row;
  577.     ccol = col;
  578.     caret = dot;
  579.     if (viewcaret) {
  580.     BringToView(crow, ccol);
  581.     }
  582.     ShowCaret();
  583. }
  584.  
  585. void TextViewer::Caret (Coord r, Coord c) {
  586.     HideCaret();
  587.     crow = -r;
  588.     ccol = c;
  589.     Position(caret, crow, ccol);
  590.     if (viewcaret) {
  591.     BringToView(crow, ccol);
  592.     }
  593.     ShowCaret();
  594. }
  595.  
  596. void TextViewer::View () {
  597.     BringToView(-row, col);
  598. }
  599.  
  600. void TextViewer::View (Coord r, Coord c) {
  601.     BringToView(-r, c);
  602. }
  603.  
  604. void TextViewer::GoTo (Coord r, Coord c) {
  605.     row = -r;
  606.     col = c;
  607.     Position(dot, row, col);
  608. }
  609.  
  610. void TextViewer::GetPos (Coord& r, Coord& c) {
  611.     r = -row;
  612.     c = col;
  613. }
  614.  
  615. void TextViewer::Margin (int m) {
  616.     margin = m;
  617. }
  618.  
  619. void TextViewer::Indent (int i) {
  620.     margin += i;
  621.     if (margin < 0) {
  622.     margin = 0;
  623.     }
  624. }
  625.  
  626. void TextViewer::Insert (int rows, int cols) {
  627.     boolean save = overwrite;
  628.     overwrite = false;
  629.     Coord newcol = col + cols;
  630.     Coord newrow = row - rows;
  631.     if (newcol < perspective->x0) {
  632.     newcol = perspective->x0;
  633.     }
  634.     Coord toprow = perspective->y0 + perspective->height - 1;
  635.     if (newrow > toprow) {
  636.     newrow = toprow;
  637.     newcol = perspective->x0;
  638.     }
  639.     if (newrow < row) {
  640.     TextLine* splitline = dot->Split(col-perspective->x0);
  641.     int shift = (row-newrow) * shape->vunits;
  642.     if (canvas != nil) {
  643.         Coord yy = YPix(row);
  644.         output->Copy(canvas, 0, 0, xmax, yy - 1, canvas, 0, -shift);
  645.         output->ClearRect(canvas, 0, yy - shift, xmax, yy - 1);
  646.     }
  647.     AddLines(dot->below, row-newrow);
  648.     GoTo(-newrow, perspective->x0);
  649.     dot->Merge(splitline);
  650.     delete splitline;
  651.     } else {
  652.     TextLine* splitline = dot->Split(col-perspective->x0);
  653.     int shift = (newrow-row) * shape->vunits;
  654.     if (canvas != nil) {
  655.         Coord yy = YPix(row);
  656.         output->Copy(canvas, 0, -shift, xmax, yy - 1, canvas, 0, 0);
  657.         Redraw(0, 0, xmax, shift - 1);
  658.     }
  659.     RemoveLines(dot->below, newrow-row);
  660.     GoTo(-newrow, perspective->x0);
  661.     GoTo(-newrow, dot->length - perspective->x0 + 2);
  662.     dot->Merge(splitline);
  663.     delete splitline;
  664.     }
  665.     if (newcol > col) {
  666.     Spaces(newcol - col);
  667.     } else if (newcol < col) {
  668.     dot->Delete(newcol-perspective->x0, col-newcol);
  669.     }
  670.     if (!buffer) {
  671.     Flush();
  672.     }
  673.     overwrite = save;
  674. }
  675.  
  676. void TextViewer::String (const char* s, int len) {
  677.     if (overwrite) {
  678.     dot->Replace(col-1, s, len, style);
  679.     } else {
  680.     dot->Insert(col-1, s, len, style);
  681.     }
  682.     Coord w = painter->GetFont()->Width(dot->text, dot->length);
  683.     if (w > perspective->width* shape->hunits) {
  684.     perspective->width = w / shape->hunits + 1;
  685.     }
  686.     if (!buffer) {
  687.     perspective->Update();
  688.     FlushLine(dot, YPix(row));
  689.     }
  690.     GoTo(-row, col+len);
  691. }
  692.  
  693. void TextViewer::String (const char* s) {
  694.     String(s, strlen(s));
  695. }
  696.  
  697. void TextViewer::NewLine () {
  698.     if (!overwrite) {
  699.     Insert(1, - (col-perspective->x0));
  700.     } else {
  701.     EndLine();
  702.     if (dot == bottom || dot->below->size == 0) {
  703.         Insert(1, - (col-perspective->x0));
  704.     } else {
  705.         GoTo(-row+1, perspective->x0);
  706.     }
  707.     }
  708.     StyleSet oldstyle = style;
  709.     style = StyleSet();
  710.     Spaces(margin);
  711.     style = oldstyle;
  712. }
  713.  
  714. void TextViewer::Rubout (int count) {
  715.     if (overwrite) {
  716.     dot->Blank(col-1, count);
  717.     } else {
  718.     dot->Delete(col-1, count);
  719.     }
  720.     if (!buffer) {
  721.     FlushLine(dot, YPix(row));
  722.     }
  723. }
  724.  
  725. void TextViewer::Tab (int spacing) {
  726.     int newcol = ((col-perspective->x0)/spacing + 1) * spacing + 1;
  727.     Spaces(newcol - col);
  728. }
  729.  
  730. void TextViewer::Spaces (int count) {
  731.     static const char* spaces = "                              ";
  732.     int l = strlen(spaces);
  733.     while (count/l > 0) {
  734.     String(spaces, l);
  735.     count -= l;
  736.     }
  737.     if (count > 0) {
  738.     String(spaces, count);
  739.     }
  740. }
  741.  
  742. void TextViewer::EndLine () {
  743.     dot->EndLine(col - perspective->x0);
  744. }
  745.  
  746. void TextViewer::EndText () {
  747.     EndLine();
  748.     TextLine* l = dot;
  749.     int count = 0;
  750.     while (l->below != nil && l->below->size > 0) {
  751.     ++count;
  752.     l = l->below;
  753.     }
  754.     RemoveLines(l->below, count);
  755. }
  756.  
  757. void TextViewer::Flush () {
  758.     perspective->Update();
  759.     HideCaret();
  760.     TextLine* begin = FindLine(perspective->cury);
  761.     TextLine* end = 
  762.     FindLine(perspective->cury+perspective->curheight-1)->above;
  763.     Coord baseline = YPix(perspective->cury);
  764.     for (TextLine* t = begin; t != end; t = t->above) {
  765.     FlushLine(t, baseline);
  766.     baseline += shape->vunits;
  767.     }
  768.     ShowCaret();
  769. }
  770.